package com.group.project.hrms.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.group.project.hrms.entity.*;
import com.group.project.hrms.entity.DingResultEntity.DingDeptListEntity;
import com.group.project.hrms.entity.DingResultEntity.DingDeptStaffDetails;
import com.group.project.hrms.entity.DingResultEntity.DingLeaveStaffDetailsEntity;
import com.group.project.hrms.entity.ResultEntity.ContactBasicInfo;
import com.group.project.hrms.entity.ResultEntity.ResultEntity;
import com.group.project.hrms.service.*;
import com.group.project.hrms.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

@Slf4j
@Controller
@EnableScheduling
public class ContactBasicController {

    private static Logger logger = LoggerFactory.getLogger(ContactBasicController.class);

    @Autowired
    private IContactBasicDeptInfoService iContactBasicDeptInfoService;

    @Autowired
    private IContactBasicService iContactBasicService;

    @Autowired
    private IContactArchivesService iContactArchivesService;

    @Autowired
    private IContactArchivesWorkingService iContactArchivesWorkingService;

    @Autowired
    private IAttendanceGroupDeptsService iAttendanceGroupDeptsService;

    @Autowired
    private IAttendanceGroupStaffsService iAttendanceGroupStaffsService;

    @Autowired
    private IAttendanceGroupInfoService iAttendanceGroupInfoService;

    @Autowired
    private AttendanceUtil attendanceUtil;

    @Autowired
    private DingAccessUtils dingAccessUtils;

    @Autowired
    private ProgressUtil progressUtil;

    @Autowired
    private BasicInfoUtil basicInfoUtil;

    @Autowired
    private LogUtil logUtil;

    @Autowired
    private DateUtil dateUtil;

    @Autowired
    private IAttendanceGroupStaffAdjustRecordService iAttendanceGroupStaffAdjustRecordService;



    /**
     * 从钉钉中同步通讯录基础、通讯录档案、通讯录档案工作信息到本地数据库
     * @param request http请求
     * @return 标准返回值对象
     */
    @RequestMapping("/basic/doSyncContactsFromDing")
    @ResponseBody
    public ResultEntity doSyncContactsFromDing(HttpServletRequest request){
        Object staffName = request.getAttribute("staffName");
        ResultEntity resultEntity = this.syncContactsFromDing();
        logUtil.insertSystemEventLog(staffName.toString(), new Date(), "从钉钉中同步了通讯录", "考勤");
        return resultEntity;
    }


    /**
     * 自动按天同步通讯录 86400000 = 24小时
     */
    @Scheduled(initialDelay = 10000, fixedDelay = 86400000)
    private void autoSyncContactsFromDing(){
        Date date = new Date();
        ResultEntity resultEntity = this.syncContactsFromDing();
        List resultList = resultEntity.getDataList();
        logUtil.insertSystemEventLog("HRMS", date, "自动同步了钉钉通讯录，其中更新了在职员工数为：" + resultList.get(0) + " 更新了离职员工数为：" + resultList.get(1), "系统");
        log.info("系统在" + date + "自动更新了迅通录，其中更新了在职员工数为：" + resultList.get(0) + " 更新了离职员工数为：" + resultList.get(1));
    }

    /**
     * 同步通讯录功能函数
     * @return
     */
    private ResultEntity syncContactsFromDing(){
        ResultEntity resultEntity = new ResultEntity();
        //-----------------------从钉钉获取数据------------------------
        //获取所有部门列表信息(DingDeptListEntity - 非数据库实体类)
        List<DingDeptListEntity> deptListEntities = dingAccessUtils.getAllDingDeptListEntityFromDing();
        //获取所有部门ID下所对应的员工详情
        List<DingDeptStaffDetails> totalUserDetailsList = new ArrayList<>();
        totalUserDetailsList.addAll(dingAccessUtils.doRootDeptStaffDetailsFromDing());
        totalUserDetailsList.addAll(dingAccessUtils.doGetAllSubDeptStaffDetailsFromDing(deptListEntities));
        if(totalUserDetailsList.size() == 0){
            resultEntity.setCode("F");
            resultEntity.setMsg("钉钉中无员工");
            return resultEntity;
        }
        logger.info("钉钉中的在职员工人数为：" + totalUserDetailsList.size());

        //-----------------------从本地数据库获取数据-------------------
        List<ContactBasic> contactBasicList = iContactBasicService.selectAllContactBasicByStaffStatus(1); //通讯录基础信息表，已经离职的不在查询范围内

        logger.info("本地数据库的在职员工人数为：" + contactBasicList.size());

        //-----------------------进行数据的同步操作---------------------
        //1,通过钉钉中获取的所有部门ID下所对应的员工详情与本地数据库比对，将比对一致的员工信息进行本地更新，将本地数据库中已经不在钉钉获取的用户ID进行汇总，便于查询其离职信息
        int countOnJob = 0; //定义更新的在职员工数量
        int countLeave = 0; //定义更新的离职员工数量
        Date date = new Date(); //当前时间对象
        if(contactBasicList.size() == 0){ //如果本地通讯录没有数据，则表示这是第一次同步，执行插入操作
            for (DingDeptStaffDetails details : totalUserDetailsList
                 ) {
                ContactBasic contactBasic = iContactBasicService.selectContactBasicByUnID(details.getUnionid());
                if(null == contactBasic){
                    countOnJob = countOnJob + this.insertStaffInfo(details, date);
                    ProgressUtil.percent = progressUtil.doComputingProgressPercent(countOnJob, totalUserDetailsList.size());
                }
            }
        }else{
            //如果本地数据库有数据，则执行比对更新操作
            List<ContactBasic> foundList = new ArrayList<>();
            for (DingDeptStaffDetails details : totalUserDetailsList
                 ) {
                ContactBasic cb = iContactBasicService.selectContactBasicByUnID(details.getUnionid());
                if(null != cb){  //找到则更新（三张表）

                    foundList.add(cb); //缓存存在的员工信息

                    cb.setmTime(date);
                    cb.setDept(JSON.toJSONString(details.getDept_id_list()));
                    cb.setStaffId(details.getJob_number());
                    cb.setStaffName(details.getName());
                    cb.setTitle(details.getTitle());
                    countOnJob = countOnJob + iContactBasicService.updateContactBasic(cb);

                    ContactArchives archives = iContactArchivesService.selectOneContactArchivesByContactID(cb.getContactId());
                    archives.setmTime(date);
                    archives.setEmailAddr(details.getEmail());
                    archives.setMobile(details.getMobile());
                    archives.setWorkPlace(details.getWork_place());
                    archives.setRemark(details.getRemark());
                    iContactArchivesService.updateContactArchives(archives);
                }else{
                    //找不到则插入（三张表）
                    countOnJob = countOnJob + this.insertStaffInfo(details, date);
                }
                ProgressUtil.percent = progressUtil.doComputingProgressPercent(countOnJob, totalUserDetailsList.size());
            }

            List<ContactBasic> leftList = new ArrayList<>();
            if(contactBasicList.size() !=0 && foundList.size() != 0){
                for (ContactBasic contactBasic : contactBasicList
                     ) {
                    if(!basicInfoUtil.isInContactBasicLoop(foundList, contactBasic)){
                        leftList.add(contactBasic);
                    }
                }
            }

            logger.info("钉钉通讯录中在本地存在的员工数量为：" + foundList.size());
            logger.info("钉钉通讯录与本地通讯录员工在同步前的差异化数量为：" + leftList.size());

            if(leftList.size() != 0){ //2,如果剩余有员工，说明这些员工已经不在钉钉在职人员中，则向本地数据库标记离职人员信息
                List<String> leftUserIds = dingAccessUtils.doGetUserIds(leftList);
                List<DingLeaveStaffDetailsEntity> leaveStaffs = new ArrayList<>();
                leaveStaffs = dingAccessUtils.doGetLeaveStaffDetailsListByUserIDs(leaveStaffs, leftUserIds);
                for (DingLeaveStaffDetailsEntity dls : leaveStaffs
                     ) {
                    for (ContactBasic cb : leftList
                         ) {
                        if(dls.getUserid().equals(cb.getDingUserid())){
                            cb.setmTime(date);
                            cb.setStaffStatus(2); //2表示离职
                            countLeave = countLeave + iContactBasicService.updateContactBasic(cb);
                            ContactArchives contactArchives = iContactArchivesService.selectOneContactArchivesByContactID(cb.getContactId());
                            contactArchives.setmTime(date);
                            contactArchives.setStaffStatus(2);
                            iContactArchivesService.updateContactArchives(contactArchives);
                            ContactArchivesWorking contactArchivesWorking = iContactArchivesWorkingService.selectOneContactArchivesWorkingByContactID(cb.getContactId());
                            contactArchivesWorking.setmTime(date);
                            contactArchivesWorking.setStaffStatus(2);
                            contactArchivesWorking.setLeaveActualDate(dls.getLast_work_day());
                            iContactArchivesWorkingService.updateContactArchivesWorking(contactArchivesWorking);
                        }
                    }
                }
            }
        }

        //3,向本地数据库更新部门详情
        if(null != deptListEntities && deptListEntities.size() != 0){
            for (DingDeptListEntity dle : deptListEntities
            ) {
                ContactBasicDeptInfo contactBasicDeptInfo = iContactBasicDeptInfoService.selectOneContactBasicDeptInfoByDeptID(dle.getDept_id());
                if(null == contactBasicDeptInfo){
                    //插入操作
                    contactBasicDeptInfo = new ContactBasicDeptInfo();
                    contactBasicDeptInfo.setcTime(date);
                    contactBasicDeptInfo.setDeptId(dle.getDept_id());
                    contactBasicDeptInfo.setDeptName(dle.getName());
                    contactBasicDeptInfo.setDeptSource(1); //1表示来自钉钉，2表示来自企业微信
                    iContactBasicDeptInfoService.insertContactBasicDeptInfo(contactBasicDeptInfo);
                }else {
                    //更新操作
                    contactBasicDeptInfo.setmTime(date);
                    contactBasicDeptInfo.setDeptId(dle.getDept_id());
                    contactBasicDeptInfo.setDeptName(dle.getName());
                    contactBasicDeptInfo.setDeptSource(1);
                    iContactBasicDeptInfoService.updateContactBasicDeptInfo(contactBasicDeptInfo);
                }
            }
        }
        resultEntity.setCode("S");
        resultEntity.setMsg("同步完成");
        List<Integer> countList = new ArrayList<>();
        countList.add(countOnJob);
        countList.add(countLeave);
        resultEntity.setDataList(countList);
        return resultEntity;
    }

    /**
     * 向本地数据库插入ContactBasic ContactArchives ContactArchivesWorking
     * @param details 钉钉员工详情对象集合
     * @param date 当前日期对象
     * @return 插入的数据条数
     */
    private int insertStaffInfo(DingDeptStaffDetails details, Date date){
        int count = 0;
        String contactID = UUIDUtil.createUUID(); //通讯录员工在本系统中的唯一标识
        ContactBasic contactBasic = new ContactBasic(); //创建通讯录基本信息对象
        ContactArchives contactArchives = new ContactArchives(); //创建通讯录档案基本信息对象
        ContactArchivesWorking contactArchivesWorking = new ContactArchivesWorking(); //创建通讯录档案工作信息对象

        //操作ContactBasic
        contactBasic.setcTime(date);
        contactBasic.setContactId(contactID);
        contactBasic.setDept(JSON.toJSONString(details.getDept_id_list()));
        contactBasic.setStaffId(details.getJob_number());
        contactBasic.setStaffName(details.name);
        contactBasic.setTitle(details.getTitle());
        contactBasic.setDingUserid(details.getUserid());
        contactBasic.setDingUnionid(details.getUnionid());
        contactBasic.setContactSource(1);
        contactBasic.setStaffStatus(1); //初始化为1，代表了该员工是正式员工
        count = count + iContactBasicService.insertContactBasic(contactBasic);

        //操作ContactArchives
        contactArchives.setcTime(date);
        contactArchives.setContactId(contactID);
        contactArchives.setHireDate(details.getHired_date());
        contactArchives.setEmailAddr(details.getEmail());
        contactArchives.setMobile(details.getMobile());
        contactArchives.setWorkPlace(details.getWork_place());
        contactArchives.setRemark(details.getRemark());
        contactArchives.setStaffStatus(1); //初始化为1，代表了该员工是正式员工
        iContactArchivesService.insertContactArchives(contactArchives);

        //操作ContactArchivesWorking - 其中，实际离职日期在更新时更新，职级暂不涉及
        contactArchivesWorking.setcTime(date);
        contactArchivesWorking.setContactId(contactID);
        contactArchivesWorking.setStaffAttribute(1); //初始化为1，代表了该员工是内部员工
        contactArchivesWorking.setStaffType(1); //初始化为1，代表了该员工是全职员工
        contactArchivesWorking.setStaffStatus(1); //初始化为1，代表了该员工是正式员工
        contactArchivesWorking.setProbationPeriod(3); //初始化为1，代表了该员工试用期默认为3个月
        contactArchivesWorking.setOnboardActualDate(details.getHired_date());
        iContactArchivesWorkingService.insertContactArchivesWorking(contactArchivesWorking);
        return count;
    }


    /**
     * 通用接口，获取通讯录基本信息并返回给前端
     * @return 标准返回值对象
     */
    @RequestMapping("/basic/doGetContactBasicList")
    @ResponseBody
    public ResultEntity doGetContactBasicList(HttpServletRequest request){
        ResultEntity resultEntity = new ResultEntity();
        List<Map> resultList = new ArrayList<>();
        Map<String, List> resultMap = new HashMap();
        List<ContactBasicInfo> basicInfoList = new ArrayList<>();
        List<AttendanceGroupInfo> groupInfos = iAttendanceGroupInfoService.selectAllAttendanceGroupInfo();
        Map<String, AttendanceGroupInfo> infoMap = attendanceUtil.getAttendanceGroupInfoMap(groupInfos);
        List<ContactBasic> list = iContactBasicService.selectAllContactBasic();
        List<ContactBasicDeptInfo> deptInfos = iContactBasicDeptInfoService.selectAllContactBasicDeptInfo(); //获取部门信息
        if(null != list && list.size() != 0){
            for (int i = 0; i < list.size(); i++) {
                ContactBasic cb = list.get(i);
                ContactBasicInfo basicInfo = new ContactBasicInfo();
                basicInfo.setId(i + 1);
                basicInfo.setKey(cb.getContactId());
                basicInfo.setName(cb.getStaffName());
                basicInfo.setJobNumber(cb.getStaffId());
                basicInfo.setDept(basicInfoUtil.getDeptName(cb.getDept(), deptInfos, cb.getContactSource()));
                if(cb.getContactSource() == 1){ //钉钉为1，企业微信为2，上传为3，其它为4
                    basicInfo.setSource("钉钉");
                }else if(cb.getContactSource() == 2){
                    basicInfo.setSource("企业微信");
                }else if(cb.getContactSource() == 3){
                    basicInfo.setSource("上传");
                }else{
                    basicInfo.setSource("其它");
                }
                if(cb.getStaffStatus() == 1){ //正式1、离职2
                    basicInfo.setStatus("在职");
                }else if(cb.getStaffStatus() == 2){
                    basicInfo.setStatus("离职");
                }
                AttendanceGroupDepts attendanceGroupDepts = iAttendanceGroupDeptsService.selectAttendanceGroupDeptsByDeptID(JSONArray.parseArray(cb.getDept()).getString(0));
                AttendanceGroupStaffs attendanceGroupStaffs = iAttendanceGroupStaffsService.selectOneAttendanceGroupStaffsByContactID(cb.getContactId());
                if(null != attendanceGroupDepts){
                    basicInfo.setAttendanceID(attendanceGroupDepts.getAttendanceGroupId());
                    basicInfo.setAttendanceName(infoMap.get(attendanceGroupDepts.getAttendanceGroupId()).getAttendanceGroupName());
                }
                if(null != attendanceGroupStaffs){
                    basicInfo.setAttendanceID(attendanceGroupStaffs.getContactId());
                    basicInfo.setAttendanceName(infoMap.get(attendanceGroupStaffs.getAttendanceGroupId()).getAttendanceGroupName());
                }
                basicInfoList.add(basicInfo);
            }
        }
        resultMap.put("basicInfoList", basicInfoList);
        resultMap.put("attendanceGroupInfos", groupInfos);
        resultList.add(resultMap);
        resultEntity.setCode("S");
        resultEntity.setDataList(resultList);
        return resultEntity;
    }

    /**
     * 该方法将获取本地通讯录中的联系人信息并按照部门归类，返回给前端请求者
     * @param request http请求
     * @return 标准返回值对象
     */
    @RequestMapping("/basic/doGetContactBasicListGroupByDept")
    @ResponseBody
    public ResultEntity doGetContactBasicListGroupByDept(HttpServletRequest request){
        ResultEntity resultEntity = new ResultEntity();
        List<Map> list = new ArrayList<>();
        List<ContactBasic> contactBasics = iContactBasicService.selectAllContactBasic();
        List<ContactBasicDeptInfo> deptInfos = iContactBasicDeptInfoService.selectAllContactBasicDeptInfo();
        Map contactMap = basicInfoUtil.doGetAllContactsGroupByDept(contactBasics, deptInfos);
        Map deptMap = basicInfoUtil.doGetDeptMap(deptInfos);
        list.add(contactMap);
        list.add(deptMap);
        resultEntity.setDataList(list);
        resultEntity.setCode("S");
        resultEntity.setMsg("Success");
        return resultEntity;
    }


    /**
     * 接收前端请求，获取某个员工的考勤组调整时序并返回给前端，该方法默认获取该员工全年的调整记录
     * @param map
     * @param request
     * @return
     */
    @RequestMapping("/basic/doGetStaffAdjustGroupInfo")
    @ResponseBody
    public ResultEntity doGetStaffAdjustGroupInfo(@RequestBody Map map, HttpServletRequest request){
        ResultEntity resultEntity = new ResultEntity();
        Object staffName = request.getAttribute("staffName");
        if(null != map){
            Object contactID = map.get("key");
            if(null != contactID){
                int year = dateUtil.getYearByDate(new Date());
                //System.out.println(year);
                List<AttendanceGroupStaffAdjustRecord> staffAdjustRecords = iAttendanceGroupStaffAdjustRecordService.selectGroupStaffAdjustRecordByContactIDAndYear(contactID.toString(), String.valueOf(year), 2);
                //对人员异动记录按照新增操作的生效时间进行升序排列
                //定义一个比较器，按照生效日期升序排列
                staffAdjustRecords.sort((d1, d2) -> {
                    try {
                        Date dt1 = d1.getDateInForce();
                        Date dt2 = d2.getDateInForce();
                        if (dt1.getTime() > dt2.getTime()) {
                            return 1;
                        } else if (dt1.getTime() < dt2.getTime()) {
                            return -1;
                        } else {
                            return 0;
                        }
                    } catch (Exception e) {
                        logger.info("对员工考勤组调整记录做按生效日期排序时出错");
                    }
                    return 0;
                });
                resultEntity.setDataList(staffAdjustRecords);
            }
        }
        logger.info(staffName + " 在 " + new Date() + " 查询了考勤组调整记录");
        resultEntity.setCode("S");
        resultEntity.setMsg("Success");
        return resultEntity;
    }


}
